
library ieee;
library std;
use ieee.std_logic_1164.all;
use ieee.std_logic_textio.all;
use work.cpu_utils.all;
use STD.textio.all; 


entity test_bench is
	generic(
		ABUS_SIZE : integer := 32;
		DBUS_SIZE: integer := 32;
		memory_size : integer := 1024;
		Tpd : Time := unit_delay;
		clock_T0 : Time := 100 ns;
		clock_T1 : Time := 10 ns
	);
end entity test_bench;



architecture simulation of test_bench is


	subtype mem_word is std_logic_vector (DBUS_SIZE-1 downto 0);
	type mem_array is array (integer range 0 to memory_size-1) of mem_word;
	shared variable mem : mem_array;
	
	shared variable hit_memory: integer := 0;
	
	signal ABUS: std_logic_vector(ABUS_SIZE-1 downto 0);
	signal DBUS: std_logic_vector(DBUS_SIZE-1 downto 0);
	
	signal clk : bit;
	
	signal halt, reset:bit;
	signal rd, wr : std_logic;
	
	signal inited:bit;
	
	component cpu
		generic (Tpd : Time := unit_delay);
		port (
			reset : in bit;
			clock : in bit;
			d_bus : inout std_logic_vector (31 downto 0);
			a_bus : out std_logic_vector (31 downto 0);
			halt : out bit;
			rd, wr : out std_logic
		);
	end component;
	
	
begin
	
	processor: cpu
	port map(
		reset, clk, DBUS, ABUS, halt, rd, wr
	);
	
	clock : process ( clk, halt )
	  begin
		if ( halt = '0' ) then
			if ( clk = '0' ) then
				clk <= '1' after clock_T0;
			else
				clk <= '0' after clock_T1;
			end if;
		else
			clk <= '0';
		end if;
	  end process;
	
	load: process(inited, clk) --load memory
		file test_file : text;
      	variable content_line : line;
      	variable mem_addr: std_logic_vector(ABUS_SIZE-1 downto 0); 
      	variable mem_content_inst: bit_vector (DBUS_SIZE-1 downto 0);
      	variable mem_content: std_logic_vector (DBUS_SIZE-1 downto 0);
      	variable space: character;
      	variable good: boolean;
      	variable address_mem : natural;	
	begin
		if inited='0' then
			ABUS <= (ABUS'range=> 'Z' );
			DBUS <= (DBUS'range=> 'Z' );
			
			for i in 0 to memory_size-1 loop
				mem(i):=( DBUS'range=> '0' );
			end loop;
			
			file_open(test_file,"E:\ETF\VLSI\workspace\vlsi\resources\test6\test.txt",READ_MODE); 
		
		 	while ( not endfile(test_file) )loop
	     		readline(test_file, content_line);
	   			hread(content_line, mem_addr);--address
	     		read(content_line, space, good);--space
	     		read(content_line, mem_content_inst);--data
	    		
	    		mem_content := to_stdlogicvector (mem_content_inst);
	     		address_mem :=	to_integer(mem_addr);
	     		
	     		mem(address_mem):= mem_content;
     		end loop;
     		
			file_close (test_file);
			inited <= '1';
		end if;
	end process load;
	
	mem_read: process(clk, rd, ABUS)
	begin
		if rd = '0'
		  then hit_memory:=to_integer(ABUS);
		elsif rd = '1'
			then 
				DBUS <= mem(hit_memory) after Tpd;
			else
				DBUS <= (DBUS'range => 'Z');
		end if;
	end process mem_read;
	
	mem_write: process(clk, wr, ABUS, DBUS)
	begin
		if wr = '0'
		  then hit_memory:=to_integer(ABUS);
		elsif wr = '1'
			then
				mem(hit_memory) := DBUS;
		end if;
	end process mem_write;
	
	check_result: process(halt)
	file test_file : text;
      	variable content_line : line;
      	variable mem_addr: std_logic_vector(ABUS_SIZE-1 downto 0); 
      	variable mem_content_inst: bit_vector (DBUS_SIZE-1 downto 0);
      	variable exp_mem_content, mem_content: std_logic_vector (DBUS_SIZE-1 downto 0);
      	variable space: character;
      	variable good: boolean;
      	variable address_mem : integer;	
	begin
		if halt='1' then
			
			file_open(test_file,"E:\ETF\VLSI\workspace\vlsi\resources\test6\exp.txt",READ_MODE); 
	     		readline(test_file, content_line);
	   			hread(content_line, mem_addr);--address
	     		read(content_line, space, good);--space
	     		read(content_line, mem_content_inst);--data
	    		
	    		exp_mem_content := to_stdlogicvector (mem_content_inst);
	     		address_mem :=	to_integer(mem_addr);
	     		
	     		mem_content := mem(address_mem) ;
	     		if(mem_content=exp_mem_content)
	     		then
	     			report "success. exected result does match" severity note;
	     		else
	     			report "error. exected result does not match" severity error;
	     		end if;
     		
			file_close (test_file);
		end if;
	end process check_result;
	
end architecture simulation;

configuration simulation_config of test_bench is
	for simulation
			for processor: cpu
				use entity work.cpu(implementation);
			end for;
		end for;
end configuration simulation_config;